import { useSettingStore } from "@/store/setting-store.ts";
import path from "@/framework/util/path.ts";
import type { LocalVersionItem, ToolInstallVersionItem } from "@/modules/dev-env/common/types.ts";
import semver from "semver";
import { noop } from "@/framework/util/warning.ts";
import { mklink } from "@/util/system-utils.ts";
import type { BaseEnvMirror } from "@/modules/dev-env/mirror/mirror.ts";
import type { UnzipCompleteArgs } from "@common/archives-file-types.ts";
import type { EnvTableAction, EnvVariableConfig, PageConfig } from "@/modules/dev-env/store/types.ts";
import type { RowClickEventArgs, VTableColumnsType } from "@/components/framework/v-table-types.ts";
import type { VNode } from "vue";
import type { ComponentType } from "@/framework/vue/types.ts";
import { EnvTree } from "@/modules/dev-env/common/tree.ts";

/**
 * 通用环境管理
 */
export abstract class GenericEnvStore<T extends GenericEnvStore<T>, V extends LocalVersionItem = LocalVersionItem> {
  /**
   * 本类代理实例,为了保持vue的响应式,在类中的一些箭头函数中使用(this.proxy.xxx)代替(this.xxx)访问
   */
  proxy!: T;

  id?: string;
  /**
   * 已安装版本列表
   */
  versionList: V[] = [];
  /**
   * 当前系统使用版本
   */
  currentVersion: V | null = null;
  /**
   * 对本地安装列表进行排序
   */
  sort = true;

  /**
   * 正在本地扫描
   */
  loading = false;

  /**
   * 管理页面图标
   */
  icon?: string | VNode | ComponentType;
  /**
   * 管理页面扩展表格显示列
   */
  tableColumns: VTableColumnsType;
  /**
   * 管理页面下方的设置组件,设置后默认的环境变量设置等不再显示
   */
  settingsComponent?: ComponentType;
  /**
   * 扩展设置页面组件
   */
  settingExtraComponent?: ComponentType;
  /**
   * 页面配置
   */
  pageConfig?: PageConfig;

  /**
   * 表格下拉菜单功能扩展
   */
  tableActions?: EnvTableAction[];

  /**
   * 表格当前选中的行对象
   */
  selectedItem: V | null = null;

  private _settings?: ReturnType<typeof useSettingStore>;

  protected _mirrors?: BaseEnvMirror[];
  protected _envVariables?: EnvVariableConfig[];

  /**
   * @param saveDirName 保存目录名称,相对于设置中的环境安装目录
   * @param maxDepth 扫描路径深度
   */
  protected constructor(
    protected readonly saveDirName: string,
    public maxDepth = 1,
  ) {
    this.tableColumns = [];
  }

  protected get settings() {
    if (!this._settings) {
      this._settings = useSettingStore();
    }
    return this._settings;
  }

  /**
   * 安装目录
   */
  get installDir() {
    return this.getInstallDir();
  }

  protected getInstallDir() {
    return path.join(this.settings.devInstallPath, this.saveDirName);
  }

  /**
   * 获取下载路径
   * @param rpath 相对于下载目录的路径
   */
  getDownloadPath(rpath: string) {
    return this.settings.getDownloadPath(path.join(this.saveDirName, rpath));
  }

  /**
   * 从目录获取版本信息
   * @param versionDir 版本(绝对)路径
   * @protected
   */
  protected abstract getVersionInfo(versionDir: string): Promise<V | undefined>;

  protected compareVersion(a: V, b: V): number {
    try {
      return semver.compare(b.version, a.version);
    } catch (e: any) {
      console.error("compare version error", e?.message ?? e);
      return 0;
    }
  }

  /**
   * 加载本地安装版本列表
   */
  async loadLocalVersions() {
    this.loading = true;
    try {
      const installDir = this.installDir;
      const versionsDir = path.join(installDir, EnvTree.versionsDir);
      const isExistsVersionsDir = await native.fs.exists(versionsDir);
      if (!isExistsVersionsDir) {
        this.versionList = [];
      } else {
        const list = await this._loadLocalVersions(versionsDir, 1);
        if (this.sort) {
          list.sort((a, b) => this.compareVersion(a, b));
        }
        this.versionList = list;
        if (list.length > 0) {
          this.selectedItem = this.selectedItem != null ? (list.find(it => it.installPath === this.selectedItem!.installPath) ?? list[0]) : list[0];
        }
      }
    } finally {
      this.loading = false;
    }
  }

  /**
   * 递归扫描本地安装版本列表
   * @param dir 文件夹路径
   * @param depth 当前深度
   * @private
   */
  private async _loadLocalVersions(dir: string, depth: number): Promise<V[]> {
    const list: V[] = [];
    if (await native.fs.exists(dir)) {
      const subDirs = await native.fs.readdir(dir);
      for (const subDir of subDirs) {
        const versionInfo = await this.getVersionInfo(subDir);
        if (versionInfo) {
          list.push(versionInfo);
        } else if (depth < this.maxDepth) {
          const versions = await this._loadLocalVersions(subDir, depth + 1);
          list.push(...versions);
        }
      }
    }
    return list;
  }

  /**
   * 加载系统当前使用版本信息
   */
  async loadCurrentVersion() {
    const currentVersionPath = path.join(this.installDir, EnvTree.currentVersionDir);
    if (await native.fs.exists(currentVersionPath)) {
      const realVersionDir = await native.fs.readlink(currentVersionPath);
      const v = await this.getVersionInfo(realVersionDir);
      this.currentVersion = v == null ? null : v;
    } else {
      this.currentVersion = null;
    }
  }

  /**
   * 加载所有信息
   */
  loadAll() {
    return Promise.all([this.loadLocalVersions(), this.loadCurrentVersion()]);
  }

  /**
   * 删除版本并删除本地文件
   * @param version
   */
  deleteVersion(version: V) {
    this.versionList = this.versionList.filter(it => it.installPath !== version.installPath);
    if (this.selectedItem == version) {
      this.selectedItem = null;
    }
    return this.deleteVersionFile(version);
  }

  /**
   * 删除版本文件,使用nodejs api删除,有些文件可能无法删除,子类需要重写使用其他方式删除
   * @param version 版本信息
   * @protected
   */
  protected async deleteVersionFile(version: V) {
    try {
      return await native.fs.rm(version.installPath, { recursive: true, force: true, maxRetries: 3 });
    } catch (e) {
      console.error("delete version file error", version, e);
    }
  }

  /**
   * 设置系统默认版本
   * @param version
   */
  setDefault(version: LocalVersionItem) {
    const linkPath = path.resolve(this.installDir, EnvTree.currentVersionDir);
    mklink(version.installPath, linkPath)
      .then(() => this.loadCurrentVersion())
      .catch(noop);
  }

  /**
   * 获取下载源
   */
  getMirrors(): BaseEnvMirror[] {
    return (this._mirrors ||= this.getMirrors0?.() || []);
  }

  protected getMirrors0?(): BaseEnvMirror[];

  /**
   * 解压完成后的回调
   * @param e 解压完成返回参数
   * @param version 版本信息
   */
  afterUnzipComplete?(e: UnzipCompleteArgs, version: ToolInstallVersionItem): void | Promise<void>;

  /**
   * 获取环境变量配置
   */
  getEnvVariables(): EnvVariableConfig[] {
    return (this._envVariables ||= this.getEnvVariables0?.() || []);
  }

  getEnvVariables0?(): EnvVariableConfig[];

  /**
   * 表格行点击事件
   * @param e
   */
  onTableRowClick(e: RowClickEventArgs<V>): void {
    this.selectedItem = e.record;
  }
}
